#pragma once

#include "IInputManager.h"
#include "IInputListener.h"

class InputManager : public IInputManager, public OIS::KeyListener, public OIS::MouseListener{
	friend class GameEngine;
public:
	void AddListener(IInputListener* newListener);
	void RemoveListener(IInputListener* oldListener);

	bool IsKeyDown(const OIS::KeyCode &key);
	bool IsKeyUp(const OIS::KeyCode &key);

	bool IsMouseDown(const OIS::MouseButtonID &mouse);
	bool IsMouseUp(const OIS::MouseButtonID &mouse);
	const OIS::MouseState &GetMouseState();

	static IInputManager* getSingleton(){
		if(!_inputManager)
			_inputManager = new InputManager();
		return _inputManager;
	}

protected:
	static IInputManager* _inputManager;

	InputManager();
	virtual ~InputManager();

	void Initialize();
	void UpdateStarted(const Ogre::FrameEvent &gameTime);
	void UpdateEnded(const Ogre::FrameEvent &gameTime);
	void Cleanup();

    bool keyPressed(const OIS::KeyEvent &key);
    bool keyReleased(const OIS::KeyEvent &key);
    bool mouseMoved(const OIS::MouseEvent &mouse );
    bool mousePressed(const OIS::MouseEvent &mouse, OIS::MouseButtonID id);
    bool mouseReleased(const OIS::MouseEvent &mouse, OIS::MouseButtonID id);

	void NotifyKeyDown(const OIS::KeyCode &key);
	void NotifyKeyUp(const OIS::KeyCode &key);
	void NotifyKeyHeld(const OIS::KeyCode &key);

	void NotifyMouseDown(const OIS::MouseState &mouse, OIS::MouseButtonID id);
	void NotifyMouseUp(const OIS::MouseState &mouse, OIS::MouseButtonID id);
	void NotifyMouseHeld(const OIS::MouseState &mouse, OIS::MouseButtonID id);
	void NotifyMouseMoved(const OIS::MouseState &mouse);

    OIS::InputManager*	_inputMgr;
    OIS::Mouse*			_mouse;
    OIS::Keyboard*		_keyboard;
	
	std::list<OIS::KeyCode> _keysDown;
	std::list<OIS::KeyCode> _tempKeysDown;
	std::list<OIS::KeyCode>::iterator _keyIt;

	std::list<OIS::MouseButtonID> _mouseDown;
	std::list<OIS::MouseButtonID> _tempMouseDown;
	std::list<OIS::MouseButtonID>::iterator _mouseIt;

	std::vector<IInputListener*>* _listenerList;
	std::vector<IInputListener*>::iterator _listenerIt;
	std::list<IInputListener*>* _newList;
	std::list<IInputListener*>* _deadList;
};